package com.base.service;

import com.alibaba.fastjson.JSONObject;
import com.base.config.Const;
import com.base.core.constant.Constants;
import com.base.core.utils.RedisCache;
import com.google.common.collect.Maps;
import com.base.config.WXConfig;
import com.base.core.constant.Enums;
import com.base.core.utils.HttpClient;
import com.base.core.utils.BaseException;
import com.base.dao.UserMapper;
import com.base.dao.model.User;
import com.vdurmont.emoji.EmojiParser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service("userService")
public class UserService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisCache redisCache;


    /**
     * 微信登录创建
     * @param req
     * @return
     */
    @Transactional
    public Map<String, Object> login(JSONObject req) {

        Integer inviteId = req.getInteger("inviteId");
        String code = req.getString("code");

        if (StringUtils.isBlank(code)) {
            throw new BaseException(Enums.ResponseStatus.WX_AUTH_CODE_BLANK);
        }

        //H5网页授权 获取 access_token openid
        JSONObject authorizationRes = authorization(code);
        //获取 access_token openid 错误
        if (Objects.isNull(authorizationRes) || StringUtils.isNotBlank(authorizationRes.getString("errcode"))) {
            LOGGER.warn("【H5网页授权结果】：获取 access_token openid 错误：{}", authorizationRes);
            throw new BaseException(Enums.ResponseStatus.WX_AUTH_FAIL);

        }
        //获取用户信息
        JSONObject userInfoRes = getUserInfo(authorizationRes.getString("openid"), authorizationRes.getString("access_token"));

        if (Objects.isNull(userInfoRes) || StringUtils.isNotBlank(userInfoRes.getString("errcode"))) {//获取 用户信息 错误

            LOGGER.warn("【获取用户信息结果】：获取 用户信息 错误：{}", userInfoRes);
            throw new BaseException(Enums.ResponseStatus.WX_USER_INFO_FAIL);
        }

        //查询用户
        User userQ = userMapper.queryByOpenId(userInfoRes.getString("openid"));

        //用户不存在
        if (Objects.isNull(userQ)) {
            //构建用户
            userQ = buildUser(userInfoRes);
            // 邀请人
            if (Objects.nonNull(inviteId) && inviteId >0) {
                userQ.setInviteId(inviteId);
            }
            userMapper.insert(userQ);
        }

        // 有效期7天
        Date timeout = new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(7));
        Map<String, Object> returnParam = Maps.newHashMap();
        returnParam.put("expireTime", timeout);
        returnParam.put("user", userQ);

        return returnParam;
    }

    /**
     * 绑定手机号
     * @param req
     * @return
     */
    public User bindMobile(JSONObject req) {
        Integer id = req.getInteger("id");
        String phone = req.getString("phone");
        String code = req.getString("code");
        if(id <=0 || StringUtils.isBlank(phone)) {
            throw new BaseException(Enums.ResponseStatus.MISS_DATA);
        }
        User select = userMapper.selectByPrimaryKey(id);
        if (Objects.isNull(select)) {
            throw new BaseException(Enums.ResponseStatus.USER_NOT_EXIST);
        }

        //取出redis验证码
        String h5CheckCode = redisCache.getCacheObject(Constants.PHONE_CODE_KEY + phone);

        if (StringUtils.isBlank(h5CheckCode)) {
            throw new BaseException(Enums.ResponseStatus.CODE_NOT_EXPIRE);
        }
        if (!h5CheckCode.equals(code)) {
            throw new BaseException(Enums.ResponseStatus.CODE_NOT_MATCH);
        }

        select.setPhone(phone);
        userMapper.updateByPrimaryKeySelective(select);
        return select;
    }

    /**
     * ID 查询
     * @param id
     * @return
     */
    public User findById(Integer id) {
        return userMapper.selectByPrimaryKey(id);
    }

    /**
     * 开放ID查询
     * @param openId
     * @return
     */
    public User findByOpenId(String openId) {
        return userMapper.queryByOpenId(openId);
    }

    private User buildUser(JSONObject userInfo) {
        User user = new User();
        //用户的唯一标识
        user.setOpenId(userInfo.getString("openid"));
        //用户昵称
        user.setNickname(EmojiParser.parseToAliases(userInfo.getString("nickname")));
        //性别
        user.setSex(userInfo.getInteger("sex"));
        //省份
        user.setProvince(userInfo.getString("province"));
        //城市
        user.setCity(userInfo.getString("city"));
        //国家
        user.setCountry(userInfo.getString("country"));
        //用户头像
        user.setHeadPortrait(userInfo.getString("headimgurl"));
        //创建时间
        user.setCreateTime(new Date());
        return user;
    }

    /**
     * H5网页授权
     *
     * @param code code码
     * @return
     */
    private JSONObject authorization(String code) {

        try {
            //公众号appid
            String appid = WXConfig.APP_ID;
            //公众号appsecret
            String appsecret = WXConfig.APP_SECRET;

            //1.封装请求参数
            Map paramMap = new HashMap();
            //公众号appid
            paramMap.put("appid", appid);
            //公众号appsecret
            paramMap.put("secret", appsecret);
            //code
            paramMap.put("code", code);
            //grant_type
            paramMap.put("grant_type", "authorization_code");
            //2.发送请求
            HttpClient httpClient = new HttpClient("https://api.weixin.qq.com/sns/oauth2/access_token");
            //是否是 https 协议
            httpClient.setHttps(true);
            //发送的 map 数据
            httpClient.setParameter(paramMap);
            //执行 get 请求
            httpClient.get();

            //3.获取执行的结果
            JSONObject jsonResult = httpClient.getContent();
            jsonResult.put("code", 0);
            LOGGER.info("H5网页授权结果：【{}】", jsonResult);

            return jsonResult;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("【H5网页授权异常】");
            return null;
        }
    }

    /**
     * 获取用户信息
     *
     * @param openid      用户的唯一标识
     * @param accessToken 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
     * @return
     */
    private JSONObject getUserInfo(String openid, String accessToken) {

        //公众号appid
        String appid = WXConfig.APP_ID;

        try {
            //1.封装请求参数
            Map paramMap = new HashMap();
            //网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
            paramMap.put("access_token", accessToken);
            //用户的唯一标识
            paramMap.put("openid", openid);
            //返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
            paramMap.put("lang", "zh_CN");

            //2.发送请求
            HttpClient httpClient = new HttpClient("https://api.weixin.qq.com/sns/userinfo");
            //是否是 https 协议
            httpClient.setHttps(true);
            //发送的 map 数据
            httpClient.setParameter(paramMap);
            //执行 get 请求
            httpClient.get();

            //3.获取执行的结果
            JSONObject jsonResult = httpClient.getContent();
            jsonResult.put("code", 200);
            LOGGER.info("获取用户信息结果：【{}】", jsonResult);

            return jsonResult;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("【获取用户信息结果异常】");
            return null;
        }
    }

    /**
     * 刷新access_token
     *
     * @param refreshToken H5网页授权获取到的用户刷新refresh_token
     * @return
     */
    private JSONObject refreshToken(String refreshToken) {
        //公众号appid
        String appid = WXConfig.APP_ID;

        try {
            //1.封装请求参数
            Map paramMap = new HashMap();
            //公众号的唯一标识
            paramMap.put("appid", appid);
            //固定填写为 refresh_token
            paramMap.put("grant_type", "refresh_token");
            //H5网页授权获取到的用户刷新refresh_token
            paramMap.put("refresh_token", refreshToken);

            //2.发送请求
            HttpClient httpClient = new HttpClient("https://api.weixin.qq.com/sns/oauth2/refresh_token");
            //是否是 https 协议
            httpClient.setHttps(true);
            //发送的 map 数据
            httpClient.setParameter(paramMap);
            //执行 get 请求
            httpClient.get();

            //3.获取执行的结果
            JSONObject jsonResult = httpClient.getContent();
            LOGGER.info("刷新access_token结果：【{}】", jsonResult);
            return jsonResult;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("【刷新access_token异常】");
            return null;
        }
    }

    /**
     * 检验授权凭证（access_token）是否有效
     *
     * @param accessToken 网页授权接口调用凭证
     * @param openId      用户唯一标识
     * @return
     */
    private JSONObject checkAccessToken(String accessToken, String openId) {
        try {
            //1.封装请求参数
            Map paramMap = new HashMap();
            //网页授权接口调用凭证
            paramMap.put("access_token", accessToken);
            //用户唯一标识
            paramMap.put("openid", openId);

            //2.发送请求
            HttpClient httpClient = new HttpClient("https://api.weixin.qq.com/sns/auth");
            //是否是 https 协议
            httpClient.setHttps(true);
            //发送的 map 数据
            httpClient.setParameter(paramMap);
            //执行 get 请求
            httpClient.get();

            //3.获取执行的结果
            JSONObject jsonResult = httpClient.getContent();
            LOGGER.info("检验授权凭证结果【{}】", jsonResult);
            return jsonResult;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("【检验授权凭证异常】");
            return null;
        }
    }
}
